home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
rfc822.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
10KB
|
588 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/* special chars from RFC822 */
const char *rspecials = "@<>()[];:.,\\\"";
/* MIME specials */
const char *tspecials = "@<>()[];:.,\\\"?/=";
/* word specials */
const char *wspecials = " @<>()[];:,\\\"";
/* ----------------------------------------------------------------------------
* RFC822 parsing routines
*/
static const char *parse_comment (const char *s, char *comment, size_t len)
{
int n = 1;
if (comment)
len--; /* save room for the terminal \0 */
else
len = 0;
while (*s)
{
if (*s == '\\')
{
s++;
if (! *s)
break; /* don't move past a nul */
}
else if (*s == '(')
n++;
else if (*s == ')')
{
n--;
if (n == 0)
{
s++;
break;
}
}
else if (ISSPACE (*s))
{
/* collapse whitespace runs to a single char */
SKIPWS (s);
if (len)
{
*comment++ = ' '; /* convert to a single space */
len--;
}
continue;
}
if (len)
{
*comment++ = *s;
len--;
}
s++;
}
if (comment)
*comment = 0;
return (s);
}
static const char *parse_quote (const char *s, char *quote, size_t len)
{
while (*s)
{
if (*s == '\\')
{
s++;
if (!*s)
break; /* don't move past a null */
}
else if (*s == '\"')
{
s++;
break;
}
if (len > 1)
{
*quote++ = *s;
len--;
}
s++;
}
*quote = 0;
return s;
}
static void parse_mailbox (ADDRESS *a, const char *s, const char *host)
{
char *p;
if ((p = strrchr (s, '@')) != NULL)
{
*p++ = 0;
a->host = safe_strdup (p);
}
else
a->host = safe_strdup (host);
a->mailbox = safe_strdup (s);
}
static const char *parse_addrspec (ADDRESS *a, const char *s, const char *host)
{
char buf[1024];
char *p = buf;
size_t buflen = sizeof (buf);
while (*s)
{
if (*s == '(')
{
/* ignore comments inside of <> */
s = parse_comment (s, NULL, 0);
}
else if (*s == '\"')
{
size_t len;
/* FOO - this assumes that the quoted-string is the first word in the
* addrspec.
*/
s = parse_quote (s + 1, buf, sizeof (buf));
len = strlen (buf);
buflen = sizeof (buf) - len;
p = buf + len;
}
else if (*s == ':')
{
/* routing info. */
*p = 0;
safe_free ((void **) &a->adl);
a->adl = safe_strdup (buf);
p = buf;
buflen = sizeof (buflen);
s++;
}
else if (*s == '>')
{
/* end of address */
s++;
break;
}
else if (ISSPACE (*s))
{
/* skip all whitespace */
s++;
}
else
{
if (buflen > 1)
*p++ = *s;
s++;
}
}
*p = 0;
if (buf[0])
parse_mailbox (a, buf, host);
return (s);
}
static const char *parse_address (ADDRESS **a, const char *s, const char *host)
{
ADDRESS *tmp = mutt_new_address ();
char addr[1024];
char buf[1024];
char *p = addr;
size_t addrlen = sizeof (addr);
while (*s)
{
if (*s == '(')
{
s = parse_comment (s + 1, buf, sizeof (buf));
if (!tmp->personal)
tmp->personal = safe_strdup (buf);
}
else if (*s == '\"')
{
s = parse_quote (s + 1, p, addrlen);
while (*p)
{
p++;
addrlen--;
}
}
else if (*s == ':')
{
/* group mailbox format */
*p = 0;
tmp->mailbox = safe_strdup (addr);
/* reset */
p = addr;
addrlen = sizeof (addr);
s++;
break;
}
else if (*s == ';')
{
/* end of group mailbox */
*p = 0;
if (addr[0])
parse_mailbox (tmp, addr, host);
if (tmp->mailbox)
{
/* create a null entry as group terminator */
tmp->next = mutt_new_address ();
}
*a = tmp;
return (s + 1);
}
else if (*s == '<')
{
/* start of real address */
*p = 0;
if (addr[0] && !tmp->personal)
tmp->personal = safe_strdup (addr);
/* reset */
p = addr;
addrlen = sizeof (addr);
s = parse_addrspec (tmp, s + 1, host);
}
else if (*s == ',')
{
*p = 0;
if (addr[0])
parse_mailbox (tmp, addr, host);
/* reset */
p = addr;
addrlen = sizeof (addr);
s++;
break;
}
else if (ISSPACE (*s))
{
SKIPWS (s);
if (p != addr)
{
if (strchr (rspecials, *s) == NULL &&
strchr (rspecials, *(p-1)) == NULL)
{
if (p != addr)
{
if (addrlen > 1)
{
*p++ = ' ';
addrlen--;
}
}
}
}
}
else
{
if (addrlen > 1)
{
*p++ = *s++;
addrlen--;
}
}
}
*p = 0;
if (addr[0])
parse_mailbox (tmp, addr, host);
if (tmp->personal || tmp->mailbox || tmp->adl || tmp->host)
*a = tmp;
else
mutt_free_address (&tmp);
return (s);
}
void rfc822_parse_adrlist (ADDRESS **a, const char *s, const char *host)
{
ADDRESS *pa = *a;
ADDRESS *tmp;
while (pa && pa->next)
pa = pa->next;
while (*s)
{
tmp = NULL;
SKIPWS (s);
s = parse_address (&tmp, s, host);
if (pa)
pa->next = tmp;
else
*a = pa = tmp;
while (pa && pa->next)
pa = pa->next;
}
}
/* ----------------------------------------------------------------------------
* RFC822 writing routines
*/
int rfc822_cat (char *d, size_t dlen, const char *s, const char *specials)
{
size_t l;
l = strlen (d);
d += l;
dlen -= l;
if (strpbrk (s, specials) != NULL)
{
dlen--; /* save room for the \0 */
if (dlen < 2)
return (-1);
*d++ = '\"';
dlen--;
while (*s)
{
if (*s == '\"')
{
if (dlen < 2)
return (-1);
*d++ = '\\';
dlen--;
}
else if (dlen < 1)
return (-1);
*d++ = *s++;
dlen--;
}
if (dlen < 1)
return (-1);
*d++ = '\"';
*d = 0;
}
else
strfcpy (d, s, dlen);
return 0;
}
int rfc822_address (char *s, size_t len, ADDRESS *a)
{
size_t l = strlen (s);
s += l;
len -= l;
if (a->adl)
{
strfcpy (s, a->adl, len);
l = strlen (s);
s += l;
len -= l;
if (len < 2)
{
*s = 0;
return (-1);
}
*s++ = ':';
len--;
}
if (a->mailbox)
{
if (rfc822_cat (s, len, a->mailbox, wspecials) == -1)
return (-1);
l = strlen (s);
s += l;
len -= l;
if (a->host)
{
if (*a->host != '@')
{
if (len < 2)
{
*s = 0;
return (-1);
}
*s++ = '@';
len--;
strfcpy (s, a->host, len);
l = strlen (s);
s += l;
len -= l;
}
}
else
{
/* group mailbox */
if (len < 3)
{
*s = 0;
return (-1);
}
*s++ = ':';
*s++ = ' ';
*s = 0;
}
}
else if (!a->host)
{
/* end of group mailbox */
if (len < 2)
{
*s = 0;
return (-1);
}
*s++ = ';';
*s = 0;
}
return 0;
}
int rfc822_write_address (char *s, size_t len, ADDRESS *a)
{
size_t l = strlen (s);
s += l;
len -= l;
if (l)
{
/* previous stuff, add a comma to separate addresses */
if (len < 3)
return (-1);
*s++ = ',';
*s++ = ' ';
*s = 0;
len -= 2;
}
while (a)
{
if (a->personal)
{
if (rfc822_cat (s, len, a->personal, rspecials) == -1)
return (-1);